package com.yishe.util.document;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.BeanUtils;

import com.fr.third.org.apache.poi.hssf.usermodel.HSSFCell;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFCellStyle;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFComment;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFFont;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFPatriarch;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFRichTextString;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFRow;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFSheet;
import com.fr.third.org.apache.poi.hssf.usermodel.HSSFWorkbook;
import com.fr.third.org.apache.poi.hssf.util.HSSFColor;
import com.fr.third.org.apache.poi.hssf.util.Region;
import com.yishe.framework.ui.easyui.Column;

public class ExcelExport<T> {

	public void export(String[] headers, Collection<T> dataset, OutputStream out) {
		// exportExcel( null, dataset, out);
	}

	public void export(List<Column>[] headers, List<Map<String, Object>> dataset, OutputStream out) {
		// exportExcel( headers, dataset, out);
	}

	public void export(List<Column>[] headers, Collection<T> dataset, OutputStream out) {
		// exportExcel( headers, dataset, out);
	}

	private SimpleDateFormat defaultDateFormat = new SimpleDateFormat("yyyy-MM-dd");
	private String excelTitle = " EXCEL 文档 ";
	private short defaultColumnWidth = 15;

	public void setDateFormat(SimpleDateFormat dateFormat) {
		defaultDateFormat = dateFormat;
	}
	public void setExcelTitle(String excelTitle) {
		this.excelTitle = excelTitle;
	}

	private HSSFCellStyle createHeadStyle(HSSFWorkbook workbook) {
		HSSFCellStyle style = workbook.createCellStyle();// 生成一个样式
		// 设置这些样式
		style.setFillForegroundColor(HSSFColor.WHITE.index);
		style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);
		style.setBorderTop(HSSFCellStyle.BORDER_THIN);
		style.setAlignment(HSSFCellStyle.ALIGN_CENTER);

		HSSFFont font = workbook.createFont();// 生成一个字体
		font.setColor(HSSFColor.BLACK.index);
		font.setFontHeightInPoints((short) 12);
		font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		// 把字体应用到当前的样式
		style.setFont(font);
		return style;
	}

	private HSSFCellStyle createBodyStyle(HSSFWorkbook workbook) {
		HSSFCellStyle style = workbook.createCellStyle();// 生成一个样式
		// 生成并设置另一个样式
		style.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);
		style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);
		style.setBorderTop(HSSFCellStyle.BORDER_THIN);
		style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
		// 生成另一个字体
		HSSFFont font = workbook.createFont();
		font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
		style.setFont(font);// 把字体应用到当前的样式
		return style;
	}

	private HSSFSheet createSheet(HSSFWorkbook workbook) {
		HSSFSheet sheet = workbook.createSheet(excelTitle);// 生成一个表格
		sheet.setDefaultColumnWidth(defaultColumnWidth);// 设置表格默认列宽度
		// 声明一个画图的顶级管理器
		HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
		// 定义注释的大小和位置 , 详见文档
		HSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0, 0, 0, 0, (short) 4, 2, (short) 6, 5));
		// 设置注释内容
		comment.setString(new HSSFRichTextString(" 可以在 POI 中添加注释！ "));
		// 设置注释作者，当鼠标移动到单元格上是可以在状态栏中看到该内容 .
		comment.setAuthor("leno");
		return sheet;
	}

	/**
	 * <pre>
	 * @param headers 表格属性列名数组
	 * @param dataset 需要显示的数据集合 , 集合中一定要放置符合 javabean 风格的类的对象。 此方法支持的 javabean 属性的数据类型有基本数据类型及 String,Date,byte[]( 图片数据 )
	 * @param out 与输出设备关联的流对象，可以将 EXCEL 文档导出到本地文件或者网络中
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IOException 
	 * </pre>
	 */
	@SuppressWarnings("unchecked")
	public void exportExcel(List<Column>[] headers, Collection<T> dataset, OutputStream out) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException {
		if (headers == null || headers.length == 0) {
			throw new RuntimeException("列表头不可以为空");
		}
		HSSFWorkbook workbook = new HSSFWorkbook();// 声明一个工作薄
		HSSFSheet sheet = createSheet(workbook);// 创建一个表格
		HSSFCellStyle headStyle = createHeadStyle(workbook);
		
		
		
		
		
		HSSFRow row = null;
		int rowIndex = -1;
		List<Column> allColumns = new ArrayList<Column>();
		for (short i = 0; i < headers.length; i++) {//行
			row = sheet.createRow(++rowIndex);
			for (short j = 0; j < headers[i].size(); j++) {
				Column c = headers[i].get(j);
				if (c.getRowspan() != 1 || c.getColspan() != 1) {
					sheet.addMergedRegion(new Region(i, j, i + c.getRowspan() - 1, (short) (j + c.getRowspan() - 1)));
				}
				if (c.getField() != null && !"".equals(c.getField())) {
					allColumns.add(c);
					sheet.setColumnWidth(j,(short)(c.getWidth()*256));
				}
				HSSFCell cell = row.createCell(j);
				cell.setCellStyle(headStyle);
				cell.setCellValue(new HSSFRichTextString(c.getTitle()));
			}
		}

		HSSFCellStyle bodyStyle = createBodyStyle(workbook);
		// 遍历集合数据，产生数据行
		Iterator<T> it = dataset.iterator();
		short col = -1;
		while (it.hasNext()) {
			row = sheet.createRow(++rowIndex);
			T t = (T) it.next();
			for (short i = 0; i < allColumns.size(); i++) {
				HSSFCell cell = row.createCell(++col);
				cell.setCellStyle(bodyStyle);
				Column c = allColumns.get(i);
				Object value = BeanUtils.getProperty(t, c.getField());
				String textValue = null;
				if (c.getFormatter() != null) {
					textValue = c.getFormatter().format(value, row, i + 1);
				} else {
					if (value instanceof Date) {
						Date date = (Date) value;
						textValue = defaultDateFormat.format(date);
					} else {
						if (value != null)
							textValue = value.toString();
					}
				}
				if (textValue != null) {
					Pattern p = Pattern.compile("^//d+(//.//d+)?$");
					Matcher matcher = p.matcher(textValue);
					if (matcher.matches()) {
						// 是数字当作 double 处理
						cell.setCellValue(Double.parseDouble(textValue));
					} else {
						HSSFRichTextString richString = new HSSFRichTextString(textValue);
						HSSFFont font3 = workbook.createFont();
						font3.setColor(HSSFColor.BLUE.index);
						richString.applyFont(font3);
						cell.setCellValue(richString);
					}
				}
			}
			col = -1;
		}
		workbook.write(out);
	}

	/**
	 * <pre>
	 * @param headers 表格属性列名数组
	 * @param dataset 需要显示的数据集合 , 集合中一定要放置符合 javabean 风格的类的对象。 此方法支持的 javabean 属性的数据类型有基本数据类型及 String,Date,byte[]( 图片数据 )
	 * @param out 与输出设备关联的流对象，可以将 EXCEL 文档导出到本地文件或者网络中
	 *</pre>
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 */
	@SuppressWarnings("unchecked")
	public void exportExcel(String[] headers, Collection<T> dataset, OutputStream out) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		HSSFWorkbook workbook = new HSSFWorkbook();// 声明一个工作薄
		HSSFSheet sheet = createSheet(workbook);// 创建一个表格
		HSSFRow row = null;
		int rowIndex = -1;
		if (headers != null && headers.length != 0) {
			HSSFCellStyle headStyle = createHeadStyle(workbook);
			row = sheet.createRow(++rowIndex);// 产生表格标题行
			for (short i = 0; i < headers.length; i++) {
				HSSFCell cell = row.createCell(i);
				cell.setCellStyle(headStyle);
				cell.setCellValue(new HSSFRichTextString(headers[i]));
			}
		}
		HSSFCellStyle bodyStyle = createBodyStyle(workbook);
		Iterator<T> it = dataset.iterator();// 遍历集合数据，产生数据行
		short col = -1;
		while (it.hasNext()) {
			row = sheet.createRow(++rowIndex);
			T t = it.next();
			// 利用反射，根据 javabean 属性的先后顺序，动态调用 getXxx() 方法得到属性值
			Field[] fields = t.getClass().getDeclaredFields();
			for (short i = 0; i < fields.length; i++) {
				Field field = fields[i];
				if (!field.isAnnotationPresent(Export.class)) {
					continue;
				}
				HSSFCell cell = row.createCell(++col);
				cell.setCellStyle(bodyStyle);
				Object value = BeanUtils.getProperty(t, field.getName());
				// 判断值的类型后进行强制类型转换
				String textValue = null;
				if (value instanceof Date) {
					Date date = (Date) value;
					textValue = defaultDateFormat.format(date);
				} else {
					// 其它数据类型都当作字符串简单处理
					if (value != null)
						textValue = value.toString();
				}
				// 如果不是图片数据，就利用正则表达式判断 textValue 是否全部由数字组成
				if (textValue != null) {
					Pattern p = Pattern.compile("^//d+(//.//d+)?$");
					Matcher matcher = p.matcher(textValue);
					if (matcher.matches()) {
						cell.setCellValue(Double.parseDouble(textValue));// 是数字当作 double 处理
					} else {
						HSSFRichTextString richString = new HSSFRichTextString(textValue);
						HSSFFont font3 = workbook.createFont();
						font3.setColor(HSSFColor.BLUE.index);
						richString.applyFont(font3);
						cell.setCellValue(richString);
					}
				}

			}
			col = -1;
		}
		try {
			workbook.write(out);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Retention(RetentionPolicy.RUNTIME)
	@Target(value = { ElementType.TYPE })
	public @interface Export {
		
	}

}